﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using TruckingApplication.Common;
using TruckingApplication.Dal.EntityModels;

namespace TruckingApplication.Web.Controllers
{ 
    public class OrderController : Controller
    {
        private TRUCKING_FRAMEWORK_Entities_2 db = new TRUCKING_FRAMEWORK_Entities_2();
        

        //
        // GET: /Order/

        public ViewResult Index()
        {
            // Find the User
            var thisUser = User.Identity;
            var userEmail = Membership.GetUser(thisUser.Name).Email;
            
            var resource = db.RESOURCEs.Where(r => r.email == userEmail).SingleOrDefault();

            var orders = db.ORDERs.Include("ORDER_STATUS").Include("ORDER_ADVANCE").Where(o => o.active == true);
            
            List<ORDER> relevantOrders = new List<ORDER>();
            
            // If User is Administrator))
            if (User.IsInRole("Administrator"))
            {
                // Find the COMPANY
                var company = db.COMPANies.Where(c => c.adminResourceID == resource.resourceID).SingleOrDefault();

                // Find the RESOURCE ID's of RESOURCE's for the COMPANY
                var resourcesForThisCompany = db.RESOURCE_COMPANY.Where(rc => rc.companyID == company.companyID).ToList();

                foreach (var r in resourcesForThisCompany)
                {
                    relevantOrders.AddRange(orders.Where(o => o.resourceID == r.resourceID));
                }
            }
            else
            {
                // Get only users orders
                relevantOrders.AddRange(orders.Where(o => o.resourceID == resource.resourceID));
            }

            return View(relevantOrders);
        }
        
        public ActionResult IndexPartial()
        {
            // Find the User
            var thisUser = User.Identity;
            var userEmail = Membership.GetUser(thisUser.Name).Email;

            var resource = db.RESOURCEs.Where(r => r.email == userEmail).SingleOrDefault();

            var orders = db.ORDERs.Include("ORDER_STATUS").Include("ORDER_ADVANCE").Where(o => o.active == true);

            List<ORDER> relevantOrders = new List<ORDER>();

            // If User is Administrator))
            if (User.IsInRole("Administrator"))
            {
                // Find the COMPANY
                var company = db.COMPANies.Where(c => c.adminResourceID == resource.resourceID).SingleOrDefault();

                // Find the RESOURCE ID's of RESOURCE's for the COMPANY
                var resourcesForThisCompany = db.RESOURCE_COMPANY.Where(rc => rc.companyID == company.companyID).ToList();

                foreach (var r in resourcesForThisCompany)
                {
                    relevantOrders.AddRange(orders.Where(o => o.resourceID == r.resourceID));
                }
            }
            else
            {
                // Get only users orders
                relevantOrders.AddRange(orders.Where(o => o.resourceID == resource.resourceID));
            }

            return View(relevantOrders.ToList());
        }
        //
        // GET: /Order/Details/5

        public ViewResult Details(long id)
        {
            ORDER order = db.ORDERs.Single(o => o.orderID == id);
            ViewBag.Broker = db.RESOURCEs.Where(r => r.resourceID == order.brokerID).SingleOrDefault().FullName;
            ViewBag.Carrier = db.RESOURCEs.Where(r => r.resourceID == order.carrierID).SingleOrDefault().FullName;
            ViewBag.Status = db.ORDER_STATUS.Where(s => s.oStatusID == order.statusID).SingleOrDefault().status;
            return View(order);
        }

        //
        // GET: /Order/Create

        public ActionResult Create()
        {
            //ViewBag.Dispatchers = new SelectList(db.RESOURCEs.Where(r => r.RESOURCE_TYPE.resourceType.ToUpper() == "DISPATCHER"), "resourceID", "FullName");

            ViewBag.Brokers = new SelectList(db.RESOURCEs.Where(r => r.RESOURCE_TYPE.resourceType.ToUpper() == "AGENT").Where(r => r.parentCompanyId == Dal.Infrastructure.UserSpecifics.CompanyID), "resourceID", "FullName");
            ViewBag.Carriers = new SelectList(db.RESOURCEs.Where(r => r.RESOURCE_TYPE.resourceType.ToUpper() == "CARRIER").Where(r => r.parentCompanyId == Dal.Infrastructure.UserSpecifics.CompanyID), "resourceID", "FullName");

            var _s = from s in db.STATEs select s;
            var stateList = new List<string>();
            foreach (var s in _s)
            {
                stateList.Add(s.sateAbv);
            }

            var states = new SelectList(stateList);

            ViewBag.PickupStates = states;
            ViewBag.DropoffStates = states;

            // Resources
            var resources =
                db.RESOURCEs.Include(r => r.RESOURCE_TYPE).Where(
                    r => r.RESOURCE_TYPE.resourceType.ToUpper() == "CARRIER");

            ViewBag.statusID = new SelectList(db.ORDER_STATUS, "oStatusID", "status");
            return View();
        } 

        //
        // POST: /Order/Create

        [HttpPost]
        public ActionResult Create(ORDER order, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    // Define dispatcher
                    order.dispatcherID = Dal.Infrastructure.UserSpecifics.ResourceID;
                    order.resourceID = Dal.Infrastructure.UserSpecifics.ResourceID;
                    order.dropOffState = collection["DropoffStates"];
                    order.pickupState = collection["PickupStates"];
                    order.carrierID = int.Parse(collection["Carriers"]);
                    order.brokerID = int.Parse(collection["Brokers"]);
                    order.active = true;
                    order.net = order.gross - order.lumperFee - order.carrierRate;
                    
                    // Save the order so it is added to the collection 
                    // so we can get its Id
                    db.ORDERs.Add(order);
                    db.Entry(order).State = EntityState.Added;
                    db.SaveChanges();

                    // See if any order advances are supplied
                    var orderAdvanceCount = collection["orderAdvancesCount"];
                    if (!String.IsNullOrEmpty(orderAdvanceCount))
                    {
                        var advancesPerOrder = int.Parse(orderAdvanceCount);
                        for (var i = 0; i < advancesPerOrder; i++)
                        {
                            var advance = new ADVANCE
                                                  {
                                                      type = collection["advanceType_" + i],
                                                      amount = decimal.Parse(collection["advanceAmt_" + i]),
                                                      referenceNumber = collection["advanceRef_" + i]
                                                  };
                            // Ensure fields are not empty
                            if (!String.IsNullOrEmpty(advance.type) && !String.IsNullOrEmpty(advance.amount.ToString()) && !String.IsNullOrEmpty(advance.referenceNumber))
                            {
                                db.ADVANCEs.Add(advance);
                                db.Entry(advance).State = EntityState.Added;
                                db.SaveChanges();

                                var orderAdvance = new ORDER_ADVANCE
                                                       {advanceID = advance.advanceID, orderID = order.orderID};
                                db.ORDER_ADVANCE.Add(orderAdvance);
                                db.Entry(orderAdvance).State = EntityState.Added;
                                db.SaveChanges();

                                // TODO: Update Order's Net
                                // Update Order's Net
                                //var newOrder = new ORDER();
                                //newOrder = db.ORDERs.Where(o => o.orderID == order.orderID).SingleOrDefault();
                                //newOrder.net -= advance.amount;
                                //db.ORDERs.Add(newOrder);
                                //db.Entry(newOrder).State = EntityState.Modified;
                                //db.SaveChanges();
                            }
                        }
                    }

                    // Add an alert
                    var alert = new ALERT
                                    {
                                        date = DateTime.Now,
                                        read = false,
                                        subject = "New Order Entered",
                                        resourceId = Dal.Infrastructure.UserSpecifics.ResourceID,
                                        content = string.Format("A new order has been entered.")
                                    };

                    db.ALERTs.Add(alert);
                    db.Entry(alert).State = EntityState.Added;
                    db.SaveChanges();

                    // Notify Broker
                    // Notify Logged In Resource
                    // Notify Administrator)))


                    return RedirectToAction("Dashboard", "Account"); 
                }catch (DbEntityValidationException dbEx){
                foreach (var validationErrors in dbEx.EntityValidationErrors){
                    foreach (var validationError in validationErrors.ValidationErrors){
                        Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                    }
                }
            }
            }

            ViewBag.statusID = new SelectList(db.ORDER_STATUS, "oStatusID", "status", order.statusID);
            return View(order);
        }
        
        //
        // GET: /Order/Edit/5
 
        public ActionResult Edit(long id)
        {
            ORDER order = db.ORDERs.Single(o => o.orderID == id);
            Infrastructure.Utilities.oldOrder = order;
            ViewBag.Brokers = new SelectList(db.RESOURCEs.Where(r => r.resourceID == order.brokerID), "resourceID", "FullName", order.brokerID);
            ViewBag.Carriers = new SelectList(db.RESOURCEs.Where(r => r.resourceID == order.carrierID), "resourceID", "FullName", order.carrierID);

            var _s = from s in db.STATEs select s;

            ViewBag.PickupStates = new SelectList(_s, "sateAbv", "sateAbv", order.pickupState);
            ViewBag.DropoffStates = new SelectList(_s, "sateAbv", "sateAbv", order.dropOffState);

            // Resources
            var resources =
                db.RESOURCEs.Include(r => r.RESOURCE_TYPE).Where(
                    r => r.RESOURCE_TYPE.resourceType.ToUpper() == "CARRIER");

            ViewBag.statusID = new SelectList(db.ORDER_STATUS, "oStatusID", "status", order.statusID);
            
            return View(order);
        }

        //
        // POST: /Order/Edit/5

        [HttpPost]
        public ActionResult Edit(ORDER order, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                
                order.orderID = 0;
                order.orderNum = long.Parse(collection["orderNum"]);
                // Define dispatcher
                order.dispatcherID = Dal.Infrastructure.UserSpecifics.ResourceID;
                order.resourceID = Dal.Infrastructure.UserSpecifics.ResourceID;
                order.dropOffState = collection["DropoffStates"];
                order.pickupState = collection["PickupStates"];
                order.carrierID = int.Parse(collection["Carriers"]);
                order.brokerID = int.Parse(collection["Brokers"]);
                order.active = true;
                order.net = order.gross - order.lumperFee - order.carrierRate;

                db.ORDERs.Add(order);
                db.Entry(order).State = EntityState.Added;
                db.SaveChanges();

                // If Order.IsPaid, update PAYMENTs table
                if (order.paidStatus == true)
                {
                    var payment = new PAYMENT();
                    // Payment Date = Today
                    payment.paymentDate = DateTime.Now;

                    // Payment Amount = ?
                    payment.paymentAmount = order.gross;

                    // Payment From = order.BrokerID
                    payment.paymentFrom = "Receiver/Broker???"; // db.RESOURCEs.Where(r => r.resourceID == order.resourceID).SingleOrDefault().FullName;

                    // Payment For = Order # ?
                    payment.paymentFor = "Order # " + order.orderID.ToString();
                    payment.paymentType = "Receivable";

                    db.PAYMENTs.Add(payment);
                    db.Entry(payment).State = EntityState.Added;
                    db.SaveChanges();

                    // Notify Administrator that an order has been paid.  Identify the order dispatcher, and carrier.  Include this within email.  
                    // Calculate payment amount for dispatcher and carrier
                    // Add an alert
                    var _alert = new ALERT
                    {
                        date = DateTime.Now,
                        read = false,
                        subject = string.Format("Order Number {0} has been PAID.", order.orderNum),
                        resourceId = Dal.Infrastructure.UserSpecifics.ResourceID,
                        content = string.Format("Order Number {0} has been PAID...", order.orderNum)
                    };

                    // Who placed the order
                    var orderDispatcher = order.resourceID;

                    // Are they dispatcher
                    var ordererResource = db.RESOURCEs.Where(r => r.resourceID == orderDispatcher).Single();

                    var orderPlacerResourceType = db.RESOURCE_TYPE.Where(rt => rt.resourceTypeID == ordererResource.resourceTypeID).Single().resourceType;

                    var comm = "";
                    if (orderPlacerResourceType == "DISPATCHER")
                    {
                        decimal commission = ordererResource.commission.Value;
                        decimal per = (commission / 100);
                        var cal = (order.gross * per);
                        // Determine the commission rate
                        comm = "(" + ordererResource.commission + "% / " + cal.ToString("C") + ")";
                    }

                    var carrier = db.RESOURCEs.Where(r => r.resourceID == order.carrierID).SingleOrDefault();
                    // Factor Fee
                    var factorFee = carrier.factoringFee;
                    // Roadside ?
                    //var carrierTrailer = db.TRAILERs.Where(t => t.resourceID == carrier.resourceID);

                    //var roadside = db.ROADSIDE_ASSISTANCE.Where(i => i.trailerID == carrierTrailer.Single().trailerID).SingleOrDefault();

                    //// Insurance ?
                    //var insurance = db.INSURANCEs.Where(i => i.trailerID == carrierTrailer.Single().trailerID).SingleOrDefault();

                    // Find order advances
                    var ordAdv = db.ORDER_ADVANCE.Where(o => o.orderID == order.orderID);

                    var message = String.Format("Order Number {0} has been paid.  <br/><br/> Order Information<hr/><table><tr><td>Order Amount: </td><td>{1}</td></tr><tr><td>Order Dispatcher: </td><td>{2}</td></tr><tr><td>Dispatcher Commission (%/$): </td><td>{3}</td></tr><tr><td>Order Carrier: </td><td>{4}</td></tr>", order.orderNum, order.gross, ordererResource.FullName, comm, carrier.FullName);

                    message += "<tr><td colspan='2'><b>Order Advance:</b></td></tr>";

                    var advanceTotal = 0.0M;
                    foreach (var oa in ordAdv)
                    {
                        message += "<tr>";
                        message += "<td>" + oa.ADVANCE.type + " - " + oa.ADVANCE.referenceNumber + "</td>";
                        message += "<td>" + oa.ADVANCE.amount.ToString("C") + "</td>";
                        message += "</tr>";
                        advanceTotal += oa.ADVANCE.amount;
                    }
                    var suggestedPaymentAmount = order.carrierRate - advanceTotal;
                    var stringCalculation = "$" + order.carrierRate.ToString() + " - " + advanceTotal.ToString();
                    message += String.Format("<tr><td>Factoring Fee:</td><td>{0}</td></tr><tr><td>Suggested Payment Amount:<br/>(Carrier Rate - Order Advances)<br/>({2})</td><td>{1}</td></tr>", factorFee, suggestedPaymentAmount, stringCalculation);
                    message += "</table>";
                    message += "<a href='../../Payment/PayNow/" + ordererResource.resourceID.ToString() + "'>Pay Dispatcher Now!</a> | <a href='../../Payment/PayNow/" + ordererResource.resourceID.ToString() + "'>Pay Carrier Now!</a> ";

                    //alert.content += string.Format("<br/>{0}", advanceInfo);
                    _alert.content = message;

                    db.ALERTs.Add(_alert);
                    db.Entry(_alert).State = EntityState.Added;
                    db.SaveChanges();

                    // Update the Alert Count for the logged in user
                    Dal.Infrastructure.UserSpecifics.AlertCount++;
                }

                var advanceInfo = "";

                // See if any order advances are supplied
                var orderAdvanceCount = collection["orderAdvancesCount"];
                if (!String.IsNullOrEmpty(orderAdvanceCount))
                {
                    var advancesPerOrder = int.Parse(orderAdvanceCount);
                    for (var i = 0; i < advancesPerOrder; i++)
                    {
                        var advance = new ADVANCE
                        {
                            type = collection["advanceType_" + i],
                            amount = decimal.Parse(collection["advanceAmt_" + i]),
                            referenceNumber = collection["advanceRef_" + i]
                        };

                        // Ensure fields are not empty
                        if (!String.IsNullOrEmpty(advance.type) && !String.IsNullOrEmpty(advance.amount.ToString()) && !String.IsNullOrEmpty(advance.referenceNumber))
                        {
                            advanceInfo +=
                                string.Format(
                                    "Advance of type {0}, for {1:C}, reference # {2} was added to this order.<br/>",
                                    advance.type, advance.amount, advance.referenceNumber);

                            // Create the Advance
                            db.ADVANCEs.Add(advance);
                            db.Entry(advance).State = EntityState.Added;
                            db.SaveChanges();

                            // Associate Advance to Order
                            var orderAdvance = new ORDER_ADVANCE { advanceID = advance.advanceID, orderID = order.orderID };
                            db.ORDER_ADVANCE.Add(orderAdvance);
                            db.Entry(orderAdvance).State = EntityState.Added;
                            db.SaveChanges();

                            // TODO: Update Order's Net
                            // Update Order's Net
                            //order.net -= advance.amount;
                            //db.ORDERs.Add(order);
                            //db.Entry(order).State = EntityState.Modified;
                            //db.SaveChanges();
                        }
                    }
                }

                var st = db.ORDER_STATUS.Where(s => s.oStatusID == order.statusID).SingleOrDefault().status;
                order.ORDER_STATUS.status = st;

                var whatChanged = Infrastructure.Utilities.OrderComparer(order);

                var orderResources = new List<decimal>();
                orderResources.Add(order.resourceID);
                orderResources.Add(order.dispatcherID);
                orderResources.Add(order.brokerID);
                orderResources.Add(order.carrierID);

                // Add an alert
                var alert = new ALERT
                {
                    date = DateTime.Now,
                    read = false,
                    subject = string.Format("Order Number {0} has been modified.", order.orderNum),
                    resourceId = Dal.Infrastructure.UserSpecifics.ResourceID,
                    content = string.Format("Order Number {0} has been modified.\n\nIt's status has been updated to {1}.", order.orderNum, db.ORDER_STATUS.Where(o => o.oStatusID == order.statusID).SingleOrDefault().status)
                };

                foreach (var change in whatChanged)
                {
                    alert.content += string.Format("<br/>{0}", change);
                }

                alert.content += string.Format("<br/>{0}", advanceInfo);

                var alredyAddedList = new List<long>();

                foreach (var resource in orderResources.Distinct())
                {
                    if (!alredyAddedList.Contains(alert.resourceId))
                    {
                        alredyAddedList.Add(alert.resourceId);
                        alert.resourceId = long.Parse(resource.ToString());
                        db.ALERTs.Add(alert);
                        db.Entry(alert).State = EntityState.Added;
                        db.SaveChanges();
                    }
                }

                // Update the Alert Count for the logged in user
                Dal.Infrastructure.UserSpecifics.AlertCount++;

                return RedirectToAction("Dashboard", "Account"); 

            }
            ViewBag.statusID = new SelectList(db.ORDER_STATUS, "oStatusID", "status", order.statusID);
            return View(order);
        }

        //
        // GET: /Order/Delete/5
 
        public ActionResult Delete(long id)
        {
            ORDER order = db.ORDERs.Single(o => o.orderID == id);
            return View(order);
        }

        //
        // POST: /Order/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(long id)
        {            
            ORDER order = db.ORDERs.Single(o => o.orderID == id);
            db.ORDERs.Remove(order);
            db.Entry(order).State = EntityState.Deleted;
            
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}